/***************************************************************************
 * Unit:    rasimg library 0.32                                            *
 * Purpose: Prototypes for general manipulation vith vector images         *
 * Modul:   vecimage.h                                                     *
 * Licency: GPL or LGPL                                                    *
 * Copyright: (c) 1998-2024 Jaroslav Fojtik                                *
 ***************************************************************************/
#ifndef _VECIMAGE_H_
#define _VECIMAGE_H_

#include "stringa.h"
#include "image.h"


#define PSS_LineColor	 1
#define PSS_LineStyle	 2
#define PSS_LineWidth	 4
#define PSS_FillColor	 8
#define PSS_LineCap	16
#define PSS_LineJoin	32

#define mm2PSu(x)   ( (float)(x)*71/25.4f )


void Font2PS(string & Text, const float FontSize, const char *FontName="Times-Roman");
void Color2PS(string & Text, const RGB_Record & TextColor);


class CpTranslator;


typedef enum
{
  FILL_NONE = 0,		// Hollow
  FILL_SOLID = 1,		// Solid
  FILL_DIAG_UP = 2,		// Finely spaced 45-degree lines
  FILL_DIAG_UP2 = 3,		// Medium spaced 45-degree lines
  FILL_DIAG_UP4 = 4,		// Coarsely spaced 45-degree lines
  FILL_DIAG_CROSSHATCH = 5,	// Fine 45-degree hatching
  FILL_DIAG_CROSSHATCH2 = 6,	// Medium 45-degree hatching
  FILL_DIAG_CROSSHATCH4 = 7,	// Coarse 45-degree hatching
  FILL_VERTICAL = 8,		// Fine vertical lines
  FILL_VERTICAL2 = 9,		// Medium vertical lines
  FILL_VERTICAL4 = 10,		// Coarse vertical lines
  FILL_GRAY_3 = 11,		// Dots density 1 (least dense)
  FILL_GRAY_6 = 12,		// Dots density 2
  FILL_GRAY_12 = 13,		// Dots density 3
  FILL_GRAY_25 = 14,		// Dots density 4
  FILL_GRAY_50 = 15,		// Dots density 5
  FILL_GRAY_75 = 16,		// Dots density 6 (densest)
				// 18 Dots (medium)
				// 19 Dots (coarse)
  FILL_HORIZONTAL = 20,		// Fine horizontal
  FILL_HORIZONTAL2 = 21,	// Medium horizontal
  FILL_HORIZONTAL4 = 22,	// Coarse horizontal
  FILL_CROSS_HATCH = 23,	// Fine 90-degree cross-hatching
  FILL_CROSS_HATCH2 = 24,	// Medium 90-degree cross-hatching
  FILL_CROSS_HATCH4 = 25,	// Coarse 90-degree cross-hatching
  FILL_DIAG_DOWN = 26,		// Fine 45-degree lines
  FILL_DIAG_DOWN2 = 27,		// Medium 45-degree lines
  FILL_DIAG_DOWN4 = 28,		// Coarse 45-degree lines
				// 29 Brick pattern (horizontal)
				// 30 Brick pattern (vertical)
				// 31 NA
				// 32 Interweaving
				// 33 NA
				// 34 NA
				// 35 Tile pattern
				// 36 Coarse lines (thick)
  FILL_SQUARES = 37,		// Alternating dark and light squares

  FILL_CROSS_HATCHx = 94,
  FILL_DIAG_DOWNx = 95,
  FILL_DIAG_CROSSHATCHx = 96,
  FILL_DIAG_UPx = 97,
  FILL_VERTICALx = 98,
  FILL_HORIZONTALx = 99,
  FILL_SQUARES2 = 107,
  FILL_PLUS = 108,
  FILL_BALLS = 109,
  FILL_TARTAN = 110,
  FILL_TRIANGLES = 111,
  FILL_SM_SQUARES = 112,
  FILL_BRICKS = 113,
  FILL_DIAG_BRICKS = 114,
  FILL_HONEYCOMB = 115,
  FILL_FISHSCALE = 116,
  FILL_ARCH = 117,
  FILL_CHAINLINK = 118,
  FILL_PATIO = 119,
  FILL_WEAVE = 120,
  FILL_WAVES = 121
} E_FILL_STYLES;


/** C type PS state, it could be copied using memcpy. */
typedef struct
{
	const CpTranslator *ConvertCpg;
	float FontSize, FontSizeW;	///< Size of font in [mm].
	float LineWidth;
	float HatchDistance;		///< PSu

	uint16_t FontWeight;
	int16_t FontOrientation10;	///< Text rotation request.

	char FontItallic;
	char dirty;
	uint8_t FillPattern;
	uint8_t FillTransparency;
	uint8_t LineStyle;
	uint8_t LineCap;		///< 0-butt caps, 1-round caps, 2-extended butt caps.
	uint8_t LineJoin;		///< 0-miter join, 1-round join, 2-bevel join.
	uint8_t PolyFillMode;		///< 0-standard; 1-alternating
	uint8_t TextAlign;		///< 0-TA_LEFT; 2-TA_RIGHT; 6-TA_CENTER

	RGB_Record FillColor;	
	RGB_Record FillBackground;

	RGB_Record LineColor;
	RGB_Record TextColor;
	
	bool FirstTimeFix;
	uint8_t inPath;
} PS_StateC;


class PS_State: public PS_StateC
{
public:
	PS_State(void);
	PS_State(const PS_State &PSS);
	~PS_State(void);
	PS_State &operator=(const PS_State & OrigPSS);
	void AttachPalette(APalette *NewPalette);
	void AttachRaster(Raster2DAbstract *NewRaster);

	RGB_Record PaperBackground;
	string FontName;
	APalette *pPalette;
	Raster2DAbstract *pRaster;
};


void PS_Attr(string & PSData, PS_State *PSS);
void FillObjectPS(float MinPolyX, float MaxPolyX, float MinPolyY, float MaxPolyY, string & PSData, PS_State *PSS);


class AbstractTransformXY
{
public:
  virtual void ApplyTransform(float &x, float &y) const = 0;
};


/** This functor class is used for resizing image data. */
class vecResizeXY: public AbstractTransformXY
{
public:
  vecResizeXY(const float iniScale) {Scale=iniScale;}

  virtual void ApplyTransform(float &x, float &y) const {x*=Scale; y*=Scale;}

  float Scale;
};


/// Square bounding box.
typedef struct
{
  float MinX;
  float MaxX;
  float MinY;
  float MaxY;
} FloatBBox;

void InitBBox(FloatBBox & bbx);
void UpdateBBox(FloatBBox & bbx, float alpha, float x, float y, float dx, float dy);
void UpdateBBox(FloatBBox & bbx, const AbstractTransformXY *Tr, const FloatBBox & bbxIn);


///////////////////////////////////////////////////////////

typedef enum
{
  ATTR_NONE =	0,
  ATTR_PEN,
  ATTR_BRUSH,
  ATTR_PALETTE,
  ATTR_RASTER,
} ATTRIB_TYPES;


class VectorAttribute
{
protected:
  mutable int RefCounter;

public:  
  void AddRef(void) {RefCounter++;}
  void Release(void) {if(--RefCounter<=0) delete this;}
  int getRefCounter(void) const {return RefCounter;}

  VectorAttribute() {RefCounter=1;}
  virtual ~VectorAttribute() {}
  virtual void prepExport(PS_State *PSS) const = 0;
  virtual int getAttribType(void) const {return ATTR_NONE;};
};

class vecPen: public VectorAttribute
{
public:
  RGB_Record LineColor;
  unsigned char LineStyle;
  unsigned char LineCap;
  unsigned char LineJoin;
  float PenWidth;

  vecPen(void);
  vecPen(const PS_State &PSS) {AttribFromPSS(PSS);}

  virtual void prepExport(PS_State *PSS) const;
  virtual int getAttribType(void) const {return ATTR_PEN;};
  void AttribFromPSS(const PS_State &PSS);
};


class vecBrush: public VectorAttribute
{
public:
  RGB_Record FillColor;
  RGB_Record FillBackground;
  unsigned char BrushStyle;		///< Fill pattern.

  vecBrush() {BrushStyle=1;}
  vecBrush(const PS_State &PSS);

  virtual void prepExport(PS_State *PSS) const;
  virtual void FeaturesEPS(uint32_t & Feature) const;
  virtual int getAttribType(void) const {return ATTR_BRUSH;};
  void AttribFromPSS(const PS_State &PSS);
};


class vecFont: public VectorAttribute
{
public:
  vecFont();
  vecFont(const PS_State &PSS);
  virtual void prepExport(PS_State *PSS) const;

  const CpTranslator *ConvertCpg;
  RGB_Record TextColor;
  float FontSize, FontSizeW;
  uint16_t Weight;
  int16_t FontOrientation10;
  char Italic;
};


class FakeAttr: public VectorAttribute
{
public:
  virtual void prepExport(PS_State *PSS) const {};
};


class attrPalette: public VectorAttribute
{
public:
  APalette *pPalette;

  attrPalette(APalette *iniPalette);
  virtual ~attrPalette();
  virtual void prepExport(PS_State *PSS) const;
  virtual int getAttribType(void) const {return ATTR_PALETTE;};
};


class attrRaster: public VectorAttribute
{
public:
  APalette *pPalette;
  Raster2DAbstract *pRaster;

  attrRaster(Raster2DAbstract *iniRaster, APalette *iniPalette=NULL);
  virtual ~attrRaster();
  virtual void prepExport(PS_State *PSS) const;
  virtual int getAttribType(void) const {return ATTR_PALETTE;};
};


class vecTransform
{
public:
  float CenterX, CenterY;
  float RotAngle;
  float TranslateX, TranslateY;
  float ScaleX, ScaleY;
 
  vecTransform(void);
  bool ApplyTransform(string &s);
};


///////////////////////////////////////////////////////////

class VectorList;


/** Base Vector object. */
class VectorObject
{
public:
  virtual temp_string Export2EPS(PS_State *PSS=NULL) const {return temp_string();}
  virtual void Export2EPS(FILE *F, PS_State *PSS) const;
  virtual void CalcBoundingBox(FloatBBox &bbx) const {}
  virtual void Transform(const AbstractTransformXY &Tx) {}
  virtual void FeaturesEPS(uint32_t & Feature) const {return;}
  virtual unsigned isInside(float xp, float yp) const {return 0;}
  virtual VectorObject *Duplicate(void)const = 0;
  virtual bool ReplaceObject(VectorObject *OrigObj, VectorObject *NewObj) {return false;}
#ifdef _DEBUG
  virtual void Dump2File(FILE *F) const {}
#endif

  virtual ~VectorObject() {NextObject=NULL;UpperCont=NULL;}
  VectorObject() {NextObject=NULL;UpperCont=NULL;}

  VectorObject *NextObject;
  VectorList *UpperCont;
};


class PsBlob: public VectorObject
{
public:
  char *Blob;

  virtual temp_string Export2EPS(PS_State *PSS=NULL) const {return temp_string(Blob);}
  //virtual void Transform(const AbstractTransformXY &Tx) {}
  virtual void FeaturesEPS(uint32_t & Feature) const;
  virtual VectorObject *Duplicate(void) const;
  virtual ~PsBlob() {NextObject=NULL; if(Blob) {free(Blob);Blob=NULL;}}
  PsBlob(char *IniBlob) {Blob=IniBlob;}
};


/** List of plain Vector objects. */
class VectorList: public VectorObject
{
public:
  virtual temp_string Export2EPS(PS_State *PSS=NULL) const;
  virtual void Export2EPS(FILE *F, PS_State *PSS=NULL) const;
  virtual void FeaturesEPS(uint32_t & Feature) const;
#ifdef _DEBUG
  virtual void Dump2File(FILE *F) const;
#endif
  VectorList(void);
  virtual ~VectorList();

  void AddObject(VectorObject *NewObj);
  virtual bool ReplaceObject(VectorObject *OrigObj, VectorObject *NewObj);
  void Append(VectorList &VectList);
  void Swap(VectorList &VectList);
  virtual VectorObject *Duplicate(void) const;

  virtual void CalcBoundingBox(FloatBBox &bbx) const;
  virtual void Transform(const AbstractTransformXY &Tx);

  VectorObject *FirstObject;
  VectorObject *LastObject;
  int VectorObjects;
};


class VectorPath: public VectorList, public vecPen, public vecBrush
{
public:
  bool Close;

  VectorPath(void): Close(false) {};

  void AttribFromPSS(const PS_State &PSS) {vecPen::AttribFromPSS(PSS);vecBrush::AttribFromPSS(PSS);}
  virtual temp_string Export2EPS(PS_State *PSS=NULL) const;
  void Export2EPS(FILE *F, PS_State *PSS) const;
#ifdef _DEBUG
  virtual void Dump2File(FILE *F) const {fprintf(F,"VectorPath\n");VectorList::Dump2File(F);fprintf(F,"~VectorPath\n");}
#endif

};


class VectorEllipse: public VectorObject, public vecPen, public vecBrush
{
public:
  VectorEllipse(float iniBottomRect, float iniTopRect, float iniRightRect, float iniLeftRect);
  VectorEllipse(const VectorEllipse & VE);
  virtual ~VectorEllipse();

  virtual temp_string Export2EPS(PS_State *PSS=NULL) const;
  virtual void Transform(const AbstractTransformXY &Tx);
  virtual void FeaturesEPS(uint32_t & Feature) const  {Feature|=EPS_DrawElipse; vecBrush::FeaturesEPS(Feature);}
  void AttribFromPSS(const PS_State &PSS) {vecPen::AttribFromPSS(PSS);vecBrush::AttribFromPSS(PSS);}
  virtual VectorObject *Duplicate(void) const;

  vecTransform *Tx;
  int bAngle, eAngle;
  float	BottomRect, TopRect, RightRect, LeftRect;
};


class VectorPie: public VectorEllipse
{
public:
  virtual VectorObject *Duplicate(void) const;

  VectorPie(float iniBottomRect, float iniTopRect, float iniRightRect, float iniLeftRect): VectorEllipse(iniBottomRect,iniTopRect,iniRightRect,iniLeftRect) {}

  virtual temp_string Export2EPS(PS_State *PSS=NULL) const;
};


class VectorLine: public VectorObject, public vecPen
{
public:
  VectorLine(int iniPointCount);
  VectorLine(float *iniBottomRect, int iniPointCount);
  VectorLine(const VectorLine &VL);
  virtual ~VectorLine();

  virtual void CalcBoundingBox(FloatBBox &bbx) const;
  virtual temp_string Export2EPS(PS_State *PSS=NULL) const;
  virtual void Transform(const AbstractTransformXY &Tx);
  virtual VectorObject *Duplicate(void) const;
#ifdef _DEBUG
  virtual void Dump2File(FILE *F) const;
#endif

  int CountPoints;
  float *Points;	///< x, y coordinate list of the line.
  bool Close;
};


/// Vector curve has possiblitity to fill curved area with solid color or hachched.
class VectorCurve: public VectorLine, public vecBrush
{
public:
  VectorCurve(int iniPointCount): VectorLine(iniPointCount) {BrushStyle=FILL_NONE;};
  VectorCurve(float *iniBottomRect, int iniPointCount): VectorLine(iniBottomRect,iniPointCount) {BrushStyle=FILL_NONE;};
  VectorCurve(const VectorCurve &VC): VectorLine(VC), vecBrush(VC) {}

  virtual void CalcBoundingBox(FloatBBox &bbx) const;
  void AttribFromPSS(const PS_State &PSS) {vecPen::AttribFromPSS(PSS);vecBrush::AttribFromPSS(PSS);}
  virtual temp_string Export2EPS(PS_State *PSS=NULL) const;

  //bool Filled;		// This should be replaced with BrushStyle=FILL_NONE.
};


class VectorPolygon: public VectorLine, public vecBrush
{
public:
  VectorPolygon(float *iniPoints, int iniPointCount): VectorLine(iniPoints,iniPointCount) {};
  VectorPolygon(const VectorPolygon &VP): VectorLine(VP), vecBrush(VP) {}
  //virtual ~VectorPolygon();			// DTOR form VectorLine is sufficient enough.

  virtual temp_string Export2EPS(PS_State *PSS=NULL) const;
  //virtual void Transform(const AbstractTransformXY &Tx);	// Inherited from VectorLine.
  virtual unsigned isInside(float xp, float yp) const;
  void AttribFromPSS(const PS_State &PSS) {vecPen::AttribFromPSS(PSS);vecBrush::AttribFromPSS(PSS);}
  virtual void FeaturesEPS(uint32_t & Feature) const  {vecBrush::FeaturesEPS(Feature);}
  virtual VectorObject *Duplicate(void) const {return new VectorPolygon(*this);}
#ifdef _DEBUG
  virtual void Dump2File(FILE *F) const;
#endif

  //unsigned isInsideX(float xp, float yp) const;
  //unsigned isInsideY(float xp, float yp) const;

  //bool Outline;		// No need for this property, Linestyle=0 is sufficient enough.
};


class VectorRectangle: public VectorObject, public vecPen, public vecBrush
{
public:
  VectorRectangle(float iniBottomRect, float iniTopRect, float iniLeftRect, float iniRightRect);
  ~VectorRectangle();

  virtual void CalcBoundingBox(FloatBBox &bbx) const;
  virtual temp_string Export2EPS(PS_State *PSS=NULL) const;
  virtual void Transform(const AbstractTransformXY &NewTx);
  virtual unsigned isInside(float xp, float yp) const;
  void AttribFromPSS(const PS_State &PSS) {vecPen::AttribFromPSS(PSS);vecBrush::AttribFromPSS(PSS);}
  virtual VectorObject *Duplicate(void) const;
#ifdef _DEBUG
  void Dump2File(FILE *F) const;
#endif

  AbstractTransformXY *Tx;
  float	BottomRect, TopRect, RightRect, LeftRect;
};


class VectorRectangleArc: public VectorRectangle
{
public:
  VectorRectangleArc(float iniBottomRect, float iniTopRect, float iniRightRect, float iniLeftRect, 
                     float iniHradius, float iniVradius);

  virtual temp_string Export2EPS(PS_State *PSS=NULL) const;
  virtual void Transform(const AbstractTransformXY &Tx);
  virtual VectorObject *Duplicate(void) const;
#ifdef _DEBUG
  void Dump2File(FILE *F) const;
#endif

  float	Hradius, Vradius;
};


/** Container for text, must be included into ::TextContainer. */
class TextObject
{
public:
  TextObject(void) {}
  TextObject(const TextObject&TC): TargetFont(TC.TargetFont), contents(TC.contents), size(TC.size), TextColor(TC.TextColor) {}

  string TargetFont;
  string contents;
  //uint16_t Weight;
  //char Itallic;
  float size;			///< Size of font in [mm].
  RGB_Record TextColor;
};


class TextContainer: public VectorObject
{
public:
  float PosX, PosY;		///< Tex start point.
  float FontOrientation;	///< Font rotation [deg]
  float RotCenterX, RotCenterY;
  uint8_t TextAlign;
  uint8_t MixMode;		///< 1 Transparent; 2 Opaque

  TextContainer();
  virtual ~TextContainer();

  virtual temp_string Export2EPS(PS_State *PSS=NULL) const;
  virtual void Transform(const AbstractTransformXY &Tx);
  virtual void FeaturesEPS(uint32_t & Feature) const;
  virtual VectorObject *Duplicate(void) const;
#ifdef _DEBUG
  void Dump2File(FILE *F) const;
#endif

  void AddText(temp_string contents, const PS_State &PSS);
  void AddText(temp_string contents, const char *font, const PS_State &PSS);

  void CalculateExtent(float &TextWidth, float &TextHeight) const;
  bool isEmpty(void) const;

  TextObject **Text;
  int TextObjects;
};



/// Vector image wrapper.
class VectorImage: public VectorList
{
public:
  mutable short UsageCount;
  PS_State PSS;

  VectorImage(void);
  VectorImage(VectorList &VecList, const PS_State & NewPSS);

  void Export2EPS(FILE *F) {PSS.LineJoin=PSS.LineCap=0;VectorList::Export2EPS(F,&PSS);}
};


//////////////////////////////////////////////////////

void DumpRaster2File(FILE *f, Raster2DAbstract *Raster, APalette *Palette,
		float CenterX, float CenterY,
		float dx, float dy, float RotAngle, int ColorMode);


class VectorRaster: public VectorObject
{
public:
  VectorRaster(float iniBottomRect, float iniTopRect, float iniRightRect, float iniLeftRect);
  VectorRaster(float iniCenterX, float iniCenterY, float dx, float dy, float alpha);
  VectorRaster(Raster2DAbstract *iniRaster, float iniCenterX, float iniCenterY, float TrDx, float TrDy, float alpha);
  VectorRaster(const VectorRaster& VR);
  virtual ~VectorRaster();

  virtual temp_string Export2EPS(PS_State *PSS=NULL) const;
  virtual void CalcBoundingBox(FloatBBox &bbx) const;
  virtual void Export2EPS(FILE *F, PS_State *PSS=NULL) const;
  virtual void Transform(const AbstractTransformXY &Tx);
  virtual void FeaturesEPS(uint32_t & Feature) const;
  virtual VectorObject *Duplicate(void) const;

  void AttachRaster(Raster2DAbstract *NewRaster);
  void AttachPalette(APalette *NewPalette);
  IMAGE_TYPE ImageType(void) const;

  float CenterX, CenterY;
  float RightCenterX, RightCenterY;
  float TopCenterX, TopCenterY;

#ifdef _DEBUG
  void Dump2File(FILE *F) const;
#endif

protected:
  Raster2DAbstract *Raster;
  APalette *Palette;
};


#endif
